typeof Symbol(): symbol
Javascript 一共有6种数据类型:Undefined、Null、Number、String、Object、Boolean。今天,我们先看看第七种:Symbol。
为什么要产生新的类型
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
可见,这个类型是提供了一个不可更新的特性,这样可以保证别人不会覆盖你的属性。下面我们来看看它的样子:
语法:Symbol([description])
let mySymbol = Symbol();
let mySymbol2 = Symbol('this is just a desction');
没有new,里面的参数只是一个描述,这就是对这个构造器的最简单解释了。
实际用途
当你第一眼看到Symbol,你会在想,什么鬼,不想用。当你知道它的特性,会让你不得不重视它。我们知道,对象的键可以用数字或字符串,但这样的话就不能保证唯一性,当我们知道symbol的特性,就可以拿它来做试验了。
可以作为键名:
let mySymbol = Symbol();
let obj = {};
obj[mySymbol] = 'hello';
如此简单的一句,obj
对象就使用了mySymbol
这个symbol作为键属性,它是一个symbol,不是一个字符串。你不能用点去访问它了,类似的,for-in去枚举一个含有symbol键的对象,也不会打印出来(看例子)。既然它的作用就是保证唯一,我们就可以在这种需求下满足了。
唯一性
let a = 'hello';
let b = 'hello';
console.log( a === b); // true
let a = Symbol('hello');
let b = Symbol('hello');
console.log( a === b); // false
已有的数据类型,我们很熟悉。再来看看symbol,即使是一样的描述,它们也是不相同的。
举一个例子:
例1
const obj = {
[Symbol('age')] : 20,
[Symbol('name')] : 'liya',
ok: true
}
for( var i in obj) {
console.log(obj[i]);
}
运行之后,你只会得到一个true。for-in 并不能访问到symbol,想要访问,你必须用到专用的api。
例2
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');
咋看也没有什么Symbol的事,事实上在ES5时代,你必须这样写:
log.levels = {
DEBUG: 1,
INFO: 2,
WARN: 3,
};
这样写的坏处是,值不是唯一的,某天如果被人把DEBUG的值改成了3,那你不是顿时懵了。用Symbol的好处在于,你不用理会它的值是什么,它只是一个占位符,并且唯一。
注册表
每个symbol是唯一的,即使两个描述一样的symbol也不相等。symbol的弱封装机制:模块创建了几个symbol,可以在任意对象上使用,无须担心与其它代码创建的属性产生冲突。它只在当前的作用域生效,如果要在全局中共享,就要在全局中注册,使用Symbol.for()
去注册。
Symbol('ok');
Symbol.for('ok');
console.log(Symbol('ok') === Symbol('ok')); // false
console.log(Symbol.for('ok') === Symbol.for('ok')); // true
第一句和第二句都是创建一个Symbol,不同的是,Symbol.for不再是每次创建不同的symbol,它会从注册表中找,找到了就会返回。无论你访问几次,都不会创建新的symbol。全局的symbol可以跨域和在多个页面中使用。
最后
查了一些资料,但也不是太过清楚,毕竟用的人还不多。期待在ES6后面能够让更多人去使用,类似Symbol这种api,大家只是瞄一眼就不再关注了,除了文档不够,更多的是设计上的问题。ES6出了有一段时间,有多少api能够深入人心,我想只有在坐的各位比较清楚。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。